using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Drawing;

namespace MSNClient
{
    public enum UserStatus
    {
        Online,
        Busy,
        BRB,
        Away,
        Phone,
        Lunch,
        Idle,
        Offline,
        Unknown
    };

    public enum SocketState
    {
        Connected,
        Disconnected
    };

    public enum Commands
    {
        NONE,   //NULL Command 
        XFR,    //Redirection to Notification server
        VER,    //Protocol version
        CVR,    //Sends version information 
        USR,    //Authentication command
        GCF,    //Unknown
        SBS,    //Unknown, After Successfully loging (USR x OK ....)
        MSG,    //Initial profile download
        CHL,    //Client challenge
        UBX,    //Send some info about user in conatct list (Additional text);
        RNG,    //Client invited to chat session
        BYE,    //Contact has left the conversation
        ANS,    //Send after RNG command
        IRO,    //Sent after a successfull ANS authentication.
        FLN,    //When contact goes offline.
        ILN,    //The current status of online user
        NLN,     //User Changed status (Busy, Away)
        JOI,     //User joined to switchboard
        ACK,     //On successful sending of message
        CAL,     //Call command was send
        QRY     //Server Response to CHL


    };

    public class MSNClient_Data
    {
        //Gets content type from MSG
        public static String GetContentType(String data)
        {
            String contentType = "Content-Type:";
            int index = data.IndexOf(contentType);//Index of the content type;
            if (index > 0)
            {
                return data.Substring(index, data.IndexOf("\r\n", index + 1) - index).Split(' ')[1];
            }
            return "";
        }
    }

    public class UserStatusInfo
    {
        public String accountName = "";
        public String displayName = "";
        public String tagName = "";
        public UserStatus userStatus = UserStatus.Unknown;
        public UserStatusInfo()
        {
        }
        public UserStatusInfo(String aDisplayName, String aTagName, UserStatus aStatus)
        {
            this.displayName = aDisplayName;
            this.tagName = aTagName;
            this.userStatus = aStatus;

        }
        public static UserStatus UserStatusFromString(String aStatus)
        {
            UserStatus status = UserStatus.Offline;
            if (aStatus == "NLN")
            {
                status = UserStatus.Online;
            }
            else if (aStatus == "BSY")
            {
                status = UserStatus.Busy;
            }
            else if (aStatus == "BRB")
            {
                status = UserStatus.BRB;
            }
            else if (aStatus == "AWY")
            {
                status = UserStatus.Away;
            }
            else if (aStatus == "PHN")
            {
                status = UserStatus.Phone;
            }
            else if (aStatus == "LUN")
            {
                status = UserStatus.Lunch;
            }
            else if (aStatus == "IDL")
            {
                status = UserStatus.Idle;
            }
            return status;
        }
    }
    /*
     * For connections where each connection have own bufferdata
     */
    public class SocketWrapper
    {
        public Socket socket;
        public String accountName = ""; //Stores inforamtion about account for which is connection was opened xxxxx@xxxx.xxx (Contact ID)
        public byte[] iReceiveBuffer;
        //Additional State for socket because Socket.Connected does not work correctly when connection lost
        public SocketState state;
        public Commands lastCommand;
        public int error;
        public bool IsAllData = true;
        public String iDataReceive;
        public SocketWrapper(AddressFamily aAddressFamily, SocketType aSocketType, ProtocolType aProtocolType)
        {
            this.socket = new Socket(aAddressFamily, aSocketType, aProtocolType);
            this.iReceiveBuffer = new byte[this.socket.ReceiveBufferSize];
            this.lastCommand = Commands.NONE;
            this.state = SocketState.Disconnected;
        }
        public int Buffer_Size
        {
            get
            {
                return this.socket.ReceiveBufferSize;
            }
        }
        public bool IsConnected()
        {
            if (this.socket.Connected && this.state == SocketState.Connected)
            {
                try
                {
                    this.socket.Send(new byte[1], 0, 0);
                    Console.WriteLine("CheckStatus->Socket is connected!");
                    return true;

                }
                catch (SocketException e)
                {
                    Console.WriteLine("Error:" + e.NativeErrorCode);
                    this.state = SocketState.Disconnected;
                    this.error = e.NativeErrorCode;
                    this.socket.Close();
                }
            }
            return false;

        }
    }

    /*
     * structure that store all information needed for showing message
     * allso will be used for writing message in history
     */
    public class MessageData
    {
        public String text;
        public String sender; //Same as accountId
        public Color textColor;
        public Font font;
        private FontStyle fontStyle;
        public bool IsOk;
        public FontStyle GetFontStyle
        { get { return this.fontStyle; } }

        public void SetFontStyle(String EFdata)//here must be passed atribute with EF=BU
        {
            this.fontStyle = FontStyle.Regular;
            if (EFdata.Contains("EF=") && EFdata.Length > 4)
            {
                if (EFdata.Contains("B"))
                    this.fontStyle = this.fontStyle | FontStyle.Bold;
                if (EFdata.Contains("I"))
                    this.fontStyle = this.fontStyle | FontStyle.Italic;
                if (EFdata.Contains("S"))
                    this.fontStyle = this.fontStyle | FontStyle.Strikeout;
                if (EFdata.Contains("U"))
                    this.fontStyle = this.fontStyle | FontStyle.Underline;
            }
        }
        public static String GreateMessage(String aData, int aTransactID)
        {
            String msgHeader = "MIME-Version: 1.0\r\n"
            + "Content-Type: text/plain; charset=UTF-8\r\n"
            + "X-MMS-IM-Format: FN=Microsoft%20Sans%20Serif; EF=B; CO=ff; CS=cc; PF=22\r\n\r\n";

            String msg = "MSG " + aTransactID + " A " + (Encoding.UTF8.GetBytes(aData).Length + msgHeader.Length) + "\r\n";
            return (msg + msgHeader + aData);
        }

        public static string GreateNudge(int aTransactID)
        {
            string nudgeMessage = "MIME-Version: 1.0\r\n"
            +"Content-Type: text/x-msnmsgr-datacast\r\n\r\n"
            +"ID: 1\r\n\r\n";
            return "MSG " + aTransactID + " N " + nudgeMessage.Length + "\r\n" + nudgeMessage;
        }


        //color string can be "0" = black or "ff" = red
        public static Color GetMessageColor(String colorString)
        {
            //red, green blue
            int[] colorCode = new int[3];
            colorCode.Initialize();
            /*
             * 0000xx
             * 00xx00
             * xx0000
             */
            int index = 0;
            if (colorString.Length <= 6)
            {
                for (int i = 1; i < colorString.Length; i += 2)
                {
                    if (colorString.Length > i)
                    {
                        try
                        {
                            colorCode[index] = int.Parse(colorString.Substring(colorString.Length - (i + 1), 2), System.Globalization.NumberStyles.HexNumber);
                        }
                        catch (Exception)
                        { }
                        index++;
                    }

                }
            }
            return Color.FromArgb(colorCode[0], colorCode[1], colorCode[2]);
        }

        public static MessageData GetMessage(String data)
        {
            MessageData message = new MessageData();
            message.IsOk = true;
            message.sender = data.Split(' ')[1];
            if (MSNClient_Data.GetContentType(data) != "text/plain;")
            {
                message.IsOk = false;
                return message;
            }

            int index = data.IndexOf("X-MMS-IM-Format");
            if (index > 0)
            {
                message.text = data.Substring(data.IndexOf("\r\n\r\n")).Trim();
                message.SetFontStyle(GetParameterFromString(data, "EF", ";", false));
                message.textColor = MessageData.GetMessageColor(GetParameterFromString(data, "CO", ";", true));
            }
            else
            {
                message.IsOk = false;
            }
            return message;
        }
        /*
         * Returns new string using borders 'begin' and 'end'
         * string = "param1 = 1234; param2 =  4321"
         * begin = "param1"
         * end = ";"
         * then result will be "param1 = 1234;"
         * or if error "" (empty string)
         * if onlyValue = true then only return "1234"
         */
        private static String GetParameterFromString(String data, String begin, String end, bool onlyValue)
        {
            String result = "";
            if (data.IndexOf(begin) > 0)
            {
                result = data.Substring(data.IndexOf(begin));
                if (result.IndexOf(end) > 0)
                {
                    result = result.Substring(0, result.IndexOf(end) + 1);
                    if (onlyValue)
                    {
                        result = result.Substring(begin.Length, result.Length - begin.Length - end.Length).Replace("=", "").Trim();
                    }
                }
                else
                {
                    result = "";
                }
            }

            return result;

        }
    }
}
